﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace Nop.Web.Framework.Security.Captcha
{
    /// <summary>
    /// Capture helper class
    /// </summary>
    public partial class Captcha
    {
        private string text;
        private int width;
        private int height;
        private string familyName;
        private Byte[] imagebytes;
        private Bitmap image;
        private Random random = new Random();

        /// <summary>
        ///  Initializes a new instance of the CaptchaImage class using the specified text, width and height.
        /// </summary>
        /// <param name="s">Text</param>
        /// <param name="width">Width</param>
        /// <param name="height">Height</param>
        public Captcha(string s, int width, int height)
        {
            this.text = s;
            this.SetDimensions(width, height);
            this.GenerateImage();
        }

        /// <summary>
        /// Initializes a new instance of the CaptchaImage class using the specified text, width, height and font family.
        /// </summary>
        /// <param name="s">Text</param>
        /// <param name="width">Width</param>
        /// <param name="height">Height</param>
        /// <param name="familyName">Font family</param>
        public Captcha(string s, int width, int height, string familyName)
        {
            this.text = s;
            this.SetDimensions(width, height);
            this.SetFamilyName(familyName);
            this.GenerateImage();
        }

        /// <summary>
        /// This member overrides Object.Finalize.
        /// </summary>
        ~Captcha()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases all resources used by this object.
        /// </summary>
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            this.Dispose(true);
        }

        /// <summary>
        /// Custom Dispose method to clean up unmanaged resources.
        /// </summary>
        /// <param name="disposing">Disposing flag</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
                // Dispose of the bitmap.
                this.image.Dispose();
        }

        /// <summary>
        /// Sets the image width and height.
        /// </summary>
        /// <param name="width">Width</param>
        /// <param name="height">Height</param>
        private void SetDimensions(int width, int height)
        {
            // Check the width and height.
            if (width <= 0)
                throw new ArgumentOutOfRangeException("width", width, "Argument out of range, must be greater than zero.");
            if (height <= 0)
                throw new ArgumentOutOfRangeException("height", height, "Argument out of range, must be greater than zero.");
            this.width = width;
            this.height = height;
        }

        /// <summary>
        /// Sets the font used for the image text.
        /// </summary>
        /// <param name="familyName">Font family</param>
        private void SetFamilyName(string familyName)
        {
            // If the named font is not installed, default to a system font.
            try
            {
                Font font = new Font(this.familyName, 12F);
                this.familyName = familyName;
                font.Dispose();
            }
            catch
            {
                this.familyName = System.Drawing.FontFamily.GenericSerif.Name;
            }
        }

        /// <summary>
        /// Creates the bitmap image.
        /// </summary>
        private void GenerateImage()
        {
            // Create a new 32-bit bitmap image.
            Bitmap bitmap = new Bitmap(this.width, this.height);

            // Create a graphics object for drawing.
            Graphics g = Graphics.FromImage(bitmap);
            Random random = new Random();            //生成随机生成器
            g.Clear(Color.White);            			//清空图片背景色
            Font font = new System.Drawing.Font("宋体", 20, (System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic));//设置字体
            System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, this.Width, this.Height), Color.Green, Color.Red, 1.2f, true);//设置笔刷
            g.DrawString(this.text, font, brush, 0, 0);//将验证码绘制到画布中
            for (int i = 0; i < 100; i++)            //画图片的前景噪音点
            {
                int x = random.Next(this.Width);
                int y = random.Next(this.Height);
                bitmap.SetPixel(x, y, Color.FromArgb(random.Next()));
            }
            //画图片的边框线
            g.DrawRectangle(new Pen(Color.Silver), 0, 0, this.Width - 1, this.Height - 1);
            //g.SmoothingMode = SmoothingMode.AntiAlias;
            //Rectangle rect = new Rectangle(0, 0, this.width, this.height);

            //// Fill in the background.
            //var hatchBrush = new HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.White);
            //g.FillRectangle(hatchBrush, rect);

            //// Set up the text font.
            //SizeF size;
            //float fontSize = rect.Height + 1;
            //Font font;
            //// Adjust the font size until the text fits within the image.
            //do
            //{
            //    fontSize--;
            //    font = new Font(this.familyName, fontSize, FontStyle.Bold);
            //    size = g.MeasureString(this.text, font);
            //} while (size.Width > rect.Width);

            //// Set up the text format.
            //var format = new StringFormat();
            //format.Alignment = StringAlignment.Center;
            //format.LineAlignment = StringAlignment.Center;

            //// Create a path using the text and warp it randomly.
            //var path = new GraphicsPath();
            //path.AddString(this.text, font.FontFamily, (int)font.Style, font.Size, rect, format);
            //float v = 4F;
            //PointF[] points =
            //{
            //    new PointF(this.random.Next(rect.Width) / v, this.random.Next(rect.Height) / v),
            //    new PointF(rect.Width - this.random.Next(rect.Width) / v, this.random.Next(rect.Height) / v),
            //    new PointF(this.random.Next(rect.Width) / v, rect.Height - this.random.Next(rect.Height) / v),
            //    new PointF(rect.Width - this.random.Next(rect.Width) / v, rect.Height - this.random.Next(rect.Height) / v)
            //};
            //var matrix = new Matrix();
            //matrix.Translate(0F, 0F);
            //path.Warp(points, rect, matrix, WarpMode.Perspective, 0F);

            //// Draw the text.
            //hatchBrush = new HatchBrush(HatchStyle.LargeConfetti, Color.LightGray, Color.DarkGray);
            //g.FillPath(hatchBrush, path);

            //// Add some random noise.
            //int m = Math.Max(rect.Width, rect.Height);
            //for (int i = 0; i < (int)(rect.Width * rect.Height / 30F); i++)
            //{
            //    int x = this.random.Next(rect.Width);
            //    int y = this.random.Next(rect.Height);
            //    int w = this.random.Next(m / 50);
            //    int h = this.random.Next(m / 50);
            //    g.FillEllipse(hatchBrush, x, y, w, h);
            //}

            // Clean up.
            font.Dispose();
            brush.Dispose();
            g.Dispose();

            // Set the image.
            this.image = bitmap;
            //reture byte data
            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, ImageFormat.Jpeg);
            this.imagebytes = stream.ToArray();
        }

        /// <summary>
        /// Text
        /// </summary>
        public string Text
        {
            get { return this.text; }
        }

        /// <summary>
        /// Image
        /// </summary>
        public Bitmap Image
        {
            get { return this.image; }
        }

        public Byte[] ImageByte
        {
            get { return this.imagebytes; }
        }

        /// <summary>
        /// Width
        /// </summary>
        public int Width
        {
            get { return this.width; }
        }

        /// <summary>
        /// Height
        /// </summary>
        public int Height
        {
            get { return this.height; }
        }
    }
}
